package com.gome.ocean.controller.gddl.proxy;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.gome.ocean.common.enums.ProxyStatus;
import com.gome.ocean.common.enums.ProxyType;
import com.gome.ocean.common.exception.ProxyBOCreateException;
import com.gome.ocean.common.utils.FormatUtil;
import com.gome.ocean.common.utils.ResponsePage;
import com.gome.ocean.dao.gddl.ProxyAdapterDAO;
import com.gome.ocean.dao.model.gddl.ClusterBO;
import com.gome.ocean.dao.model.gddl.CommandStatusVO;
import com.gome.ocean.dao.model.gddl.ConnectionStatusVO;
import com.gome.ocean.dao.model.gddl.ProcessorStatusVO;
import com.gome.ocean.dao.model.gddl.ProxyBO;
import com.gome.ocean.dao.model.gddl.ThreadPoolStatusVO;
import com.gome.ocean.service.base.AuthorityBaseController;
import com.gome.ocean.service.gddl.ClusterService;
import com.gome.ocean.service.gddl.ProxyService;
import com.gome.ocean.service.utils.ListSortUtil;



/**
 * @author haqiaolong 2016年3月28日 上午10:45:57
 * @since 5.0.0
 */
@Controller
@RequestMapping("/tddl/proxy")
public class ProxyController extends AuthorityBaseController {

    private static final Logger LOG = LoggerFactory.getLogger(ProxyController.class);

    @Autowired
    private ProxyService        proxyService;
    @Autowired
    private ClusterService      clusterService;

    @RequestMapping(value = "/insert", method = RequestMethod.GET)
    public String toInsertPage(ModelMap m) {
        List<ClusterBO> clusterBOs = clusterService.findAllClusterBOs();
        m.put("clusterBOs", clusterBOs);
        return "gddl/proxy/insert";
    }

    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage insert() {
        ResponsePage page = getResponsePage();
        String createProxyErrMsg = "创建ProxyBO时发生异常，请检查请求参数后重新提交";
        ProxyBO proxy;
        try {
            proxy = getProxyBOFromReq();
            ClusterBO cluster = clusterService.findClusterBOById(proxy.getClusterId());
            proxy.setProject(cluster.getProject());
        } catch (ProxyBOCreateException e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(createProxyErrMsg);
        }
        if (null == proxy) {
            return page.setErrorMsg(createProxyErrMsg);
        }
        try {
            boolean flag = super.permitAccess(proxy);
            if (flag) {
                if (proxyService.insertProxyBO(proxy)) {
                    return page.setSuccessMsg("创建新代理节点成功");
                } else {
                    return page.setErrorMsg("创建新代理节点失败");
                }
            }
            return page.setErrorMsg("您没有项目组权限！");
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    /**
     * 从HttpServletRequest中获取ProxyBO
     *
     * @return
     */
    private ProxyBO getProxyBOFromReq() throws ProxyBOCreateException {

        HttpServletRequest req = getHttpRequest();

        ConvertUtilsBean convertUtils = new ConvertUtilsBean();
        BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils, new PropertyUtilsBean());

        Enumeration names = req.getParameterNames();
        ProxyBO proxy = new ProxyBO();

        while (names.hasMoreElements()) {
            String name = (String) names.nextElement();
            String value = req.getParameter(name);

            try {
                beanUtils.setProperty(proxy, name, value);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new ProxyBOCreateException(e.getMessage());
            }
        }

        return proxy;
    }

    @RequestMapping(value = "/remove", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage remove(@RequestParam("id") long id) {

        ResponsePage page = getResponsePage();
        try {
            if (!permitAccess(proxyService.findProxyBOById(id))) {
                return page.setErrorMsg("您没有权限访问此代理节点记录");
            }
            if (proxyService.removeProxyBOById(id)) {
                return page.setSuccessMsg("删除代理节点成功");
            } else {
                return page.setErrorMsg("删除代理节点失败");
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage update() {
        ResponsePage page = getResponsePage();
        String updateProxyErrMsg = "更新ProxyBO时发生异常，请检查请求参数后重新提交";
        ProxyBO proxy;
        try {
            proxy = getProxyBOFromReq();
            proxy.setProject(proxyService.findProxyBOById(proxy.getId()).getProject());
        } catch (ProxyBOCreateException e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(updateProxyErrMsg);
        }
        if (null == proxy) {
            return page.setErrorMsg(updateProxyErrMsg);
        }
        try {
            if (!permitAccess(proxy)) {
                return page.setErrorMsg("您没有权限访问此代理节点记录");
            }
            if (proxyService.updateProxyBO(proxy)) {
                return page.setSuccessMsg("更新代理节点成功");
            } else {
                return page.setErrorMsg("更新代理节点失败");
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/find", method = RequestMethod.GET)
    public String findGet(ModelMap m) {
        List<ClusterBO> clusterBOs;
        try {
            if (isAdmin()) {
                clusterBOs = clusterService.findAllClusterBOs();
            } else {
                List<String> projectNames = getCurrentUserProjects();
                if (null == projectNames || projectNames.isEmpty()) {
                    m.put("errorMsg", "您不属于任何项目组，请先联系管理员为您分配项目组");
                    return "gddl/proxy/find";
                }
                clusterBOs = clusterService.findAllClusterBOsByProjects(projectNames);
            }
            m.put("clusterBOs", clusterBOs);
            return "gddl/proxy/find";
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            m.put("errorMsg", "方法执行过程中发生异常，请联系维护人员");
            return "gddl/proxy/find";
        }

    }

    @RequestMapping(value = "/find", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage find() {
        ResponsePage page = getResponsePage();
        try {
            return findEntityBachWithAuth(proxyService, "ProxyBO", true);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/findById", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findById(@RequestParam("id") long id) {
        ResponsePage page = getResponsePage();
        try {
            ProxyBO proxyBO = proxyService.findProxyBOById(id);
            if (null == proxyBO) {
                return page.emptyPage("未查询到结果");
            }

            return page.setSingleObject(proxyBO, "查询成功");

        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    @RequestMapping(value = "/findByName", method = RequestMethod.POST)
    @ResponseBody
    public ResponsePage findByName(@RequestParam("name") String name) {
        ResponsePage page = getResponsePage();
        if (StringUtils.isBlank(name)) {
            return page.setErrorMsg("请输入要查询的代理点名称");
        }
        try {
            ProxyBO proxyBO = proxyService.findProxyByName(name.trim());
            if (null == proxyBO) {
                return page.emptyPage("未查询到结果");
            }
            boolean flag = super.permitAccess(proxyBO);
            if (flag) {
                return page.setSingleObject(proxyBO, "查询成功");
            }
            return page.setErrorMsg("您没有项目组权限");
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return page.setErrorMsg(e.getMessage());
        }
    }

    /**
     * 杀死connection
     *
     * @param proxyId
     * @param connectionId
     * @param req
     * @return
     */
    @RequestMapping("/killConnection")
    @ResponseBody
    public ResponsePage killConnection(@RequestParam("proxyId") long proxyId,
                                       @RequestParam("connectionId") long connectionId, HttpServletRequest req) {
        ResponsePage page = getResponsePage();
        ProxyBO proxyBO = proxyService.findProxyBOById(proxyId);
        try {
            boolean flag = super.permitAccess(proxyBO);
            if (flag) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn(new StringBuilder().append(getCurrentUser(req))
                        .append(" | kill connection | GDDL: ")
                        .append(proxyBO.getName())
                        .append(" | connection_id:")
                        .append(connectionId)
                        .toString());
                }
                if (proxyBO.getStatus() != ProxyStatus.ACTIVE.getValue()) {
                    return page.setErrorMsg("proxy已被禁用，请仔细核对相关信息!");
                }
                ProxyAdapterDAO perfAccesser = proxyService.getAccesser(proxyId, ProxyType.MANAGER);
                if (perfAccesser == null) {
                    return page.setErrorMsg("找不到proxy node!");
                }
                if (!perfAccesser.checkConnection()) {
                    return page.setErrorMsg("proxy连接异常，请仔细核对相关信息!");
                }
                perfAccesser.killConnection(connectionId);
                return page.setSuccessMsg("连接关闭成功!");
            }
            return page.setErrorMsg("您没有项目组权限");
        } catch (Exception e) {
            return page.setErrorMsg("异常信息：" + e.toString());
        }

    }

    /**
     * offline
     *
     * @param proxyId
     * @return
     */
    @RequestMapping("/offline")
    @ResponseBody
    public ResponsePage offline(@RequestParam("proxyId") long proxyId, HttpServletRequest req) {
        ResponsePage page = getResponsePage();
        ProxyBO proxyBO = proxyService.findProxyBOById(proxyId);
        try {
            boolean flag = super.permitAccess(proxyBO);
            if (flag) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn(new StringBuilder().append(getCurrentUser(req))
                        .append(" | offline GDDL: ")
                        .append(proxyBO.getName())
                        .toString());
                }
                proxyBO.setStatus(ProxyStatus.INACTIVE.getValue());
                boolean result = false;
                try {
                    result = proxyService.updateProxyBO(proxyBO);
                } catch (Exception e) {
                    return page.setErrorMsg(e.getMessage());
                }
                if (result) {
                    return page.setSuccessMsg("下线成功!");
                }
                return page.setErrorMsg("下线失败");
            }
            return page.setErrorMsg("您没有节点权限");
        } catch (Exception e) {
            return page.setErrorMsg("异常信息：" + e.toString());
        }
    }

    /**
     * online
     *
     * @param proxyId
     * @return
     */
    @RequestMapping("/online")
    @ResponseBody
    public ResponsePage online(@RequestParam("proxyId") long proxyId, HttpServletRequest req) {
        ResponsePage page = getResponsePage();
        ProxyBO proxyBO = proxyService.findProxyBOById(proxyId);
        try {
            boolean flag = super.permitAccess(proxyBO);
            if (flag) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn(new StringBuilder().append(getCurrentUser(req))
                        .append(" | online GDDL: ")
                        .append(proxyBO.getName())
                        .toString());
                }
                proxyBO.setStatus(ProxyStatus.ACTIVE.getValue());
                boolean result = false;
                try {
                    result = proxyService.updateProxyBO(proxyBO);
                } catch (Exception e) {
                    return page.setErrorMsg(e.getMessage());
                }
                if (result) {
                    return page.setSuccessMsg("上线成功!");
                }
                return page.setErrorMsg("上线失败");
            }
            return page.setErrorMsg("您没有节点权限");
        } catch (Exception e) {
            return page.setErrorMsg("异常信息 ： " + e.toString());
        }
    }

    @RequestMapping(value = "/runStatus", method = RequestMethod.GET)
    public String toRunStatusPage(HttpServletRequest req, ModelMap m) {
        String proxyIdStr = req.getParameter("proxyId");
        if (StringUtils.isBlank(proxyIdStr)) {
            return "gddl/proxy/runStatus";
        }
        Long proxyId = Long.parseLong(proxyIdStr.trim());
        try {
            ProxyBO proxy = proxyService.findProxyBOById(proxyId);
            if (null != proxy) {
                m.put("proxy", proxy);
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            m.put("error", e.getMessage());
        }
        m.put("proxyId", proxyId);
        return "gddl/proxy/runStatus";
    }

    /**
     * 根据代理ID获取代理所有正在处理的状态
     *
     * @param proxyId
     * @return
     */
    @RequestMapping("/listProcessorStatus")
    @ResponseBody
    public ResponsePage listProcessorStatus(@RequestParam("proxyId") long proxyId) {
        ResponsePage page = getResponsePage();
        long timestamp = 0;
        ProxyAdapterDAO perfAccesser = proxyService.getAccesser(proxyId, ProxyType.MANAGER);
        if (perfAccesser == null) {
            return page.setErrorMsg("找不到proxy node!");
        }
        if (!perfAccesser.checkConnection()) {
            return page.setErrorMsg("连接异常！");
        }
        List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();

        List<ProcessorStatusVO> list = perfAccesser.listProccessorStatus();
        long a[] = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        for (ProcessorStatusVO e : list) {
            a[0] += e.getNetIn();
            a[1] += e.getNetOut();
            a[2] += e.getRequestCount();
            a[3] += e.getrQueue();
            a[4] += e.getwQueue();
            a[5] += e.getFreeBuffer();
            a[6] += e.getTotalBuffer();
            a[7] += e.getConnections();
            a[8] += e.getBc_count();
            timestamp = e.getSampleTimeStamp();

            Map<String, Object> map = new HashMap<String, Object>();
            map.put("processorId", e.getProcessorId());
            map.put("netIn", FormatUtil.formatStore(e.getNetIn()));
            map.put("netOut", FormatUtil.formatStore(e.getNetOut()));
            map.put("requestCount", FormatUtil.formatNumber(e.getRequestCount()));
            map.put("rQueue", e.getrQueue());
            map.put("wQueue", e.getwQueue());
            map.put("freeBuffer", e.getFreeBuffer());
            map.put("totalBuffer", e.getTotalBuffer());
            map.put("connections", e.getConnections());
            map.put("bc_count", e.getBc_count());
            returnList.add(map);
        }

        Map<String, Object> total = new HashMap<String, Object>();
        total.put("processorId", "TOTAL");
        total.put("netIn", FormatUtil.formatStore(a[0]));
        total.put("netOut", FormatUtil.formatStore(a[1]));
        total.put("requestCount", FormatUtil.formatNumber(a[2]));
        total.put("rQueue", a[3]);
        total.put("wQueue", a[4]);
        total.put("freeBuffer", a[5]);
        total.put("totalBuffer", a[6]);
        total.put("connections", a[7]);
        total.put("bc_count", a[8]);
        total.put("sampleTimeStamp", timestamp);
        total.put("netInC", a[0]);
        total.put("netOutC", a[1]);
        total.put("requestCountC", a[2]);
        returnList.add(total);

        return page.setJustList(returnList, "根据代理ID获取代理所有正在处理的状态!");
    }

    /**
     * 根据代理ID获取线程统计信息
     *
     * @param proxyId
     * @return
     */
    @RequestMapping("/listThreadPool")
    @ResponseBody
    private ResponsePage listThreadPool(@RequestParam("proxyId") long proxyId) {
        ResponsePage page = getResponsePage();
        ProxyAdapterDAO perfAccesser = proxyService.getAccesser(proxyId, ProxyType.MANAGER);
        if (perfAccesser == null) {
            return page.setErrorMsg("找不到proxy node!");
        }
        if (!perfAccesser.checkConnection()) {
            return page.setErrorMsg("连接异常！");
        }
        List<ThreadPoolStatusVO> pools = perfAccesser.listThreadPoolStatus();
        List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
        for (ThreadPoolStatusVO t : pools) {
            Map<String, Object> map = new HashMap<String, Object>();

            map.put("threadPoolName", t.getThreadPoolName());
            map.put("poolSize", t.getPoolSize());
            map.put("activeSize", t.getActiveSize());
            map.put("taskQueue", t.getTaskQueue());
            map.put("completedTask", FormatUtil.formatNumber(t.getCompletedTask()));
            map.put("totalTask", FormatUtil.formatNumber(t.getTotalTask()));

            returnList.add(map);
        }
        return page.setJustList(returnList, "根据代理ID获取线程统计信息!");
    }

    /**
     * 根据代理ID获取正在执行的命令
     *
     * @param proxyId
     * @return
     */
    @RequestMapping("/listCommand")
    @ResponseBody
    private ResponsePage listCommand(@RequestParam("proxyId") long proxyId) {
        ResponsePage page = getResponsePage();
        ProxyAdapterDAO perfAccesser = proxyService.getAccesser(proxyId, ProxyType.MANAGER);
        if (perfAccesser == null) {
            return page.setErrorMsg("找不到proxy node!");
        }
        if (!perfAccesser.checkConnection()) {
            return page.setErrorMsg("连接异常！");
        }
        List<CommandStatusVO> list = perfAccesser.listCommandStatus();
        List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();

        // the last element is total count
        long a[] = new long[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        for (CommandStatusVO l : list) {
            a[0] += l.getQuery();
            a[1] += l.getStmtPrepared();
            a[2] += l.getStmtExecute();
            a[3] += l.getStmtClose();
            a[4] += l.getPing();
            a[5] += l.getQuit();
            a[6] += l.getOther();
            a[7] += l.getInitDB();
            a[8] += l.getKill();

            Map<String, Object> map = new HashMap<String, Object>();
            map.put("processorId", l.getProcessorId());
            map.put("stmtPrepared", FormatUtil.formatNumber(l.getStmtPrepared()));
            map.put("stmtExecute", FormatUtil.formatNumber(l.getStmtExecute()));
            map.put("query", FormatUtil.formatNumber(l.getQuery()));
            map.put("stmtClose", FormatUtil.formatNumber(l.getStmtClose()));
            map.put("ping", FormatUtil.formatNumber(l.getPing()));
            map.put("quit", FormatUtil.formatNumber(l.getQuit()));
            map.put("other", FormatUtil.formatNumber(l.getOther()));
            map.put("kill", FormatUtil.formatNumber(l.getKill()));
            map.put("initDB", FormatUtil.formatNumber(l.getInitDB()));
            returnList.add(map);
        }

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("processorId", "Total");
        map.put("stmtPrepared", FormatUtil.formatNumber(a[1]));
        map.put("stmtExecute", FormatUtil.formatNumber(a[2]));
        map.put("query", FormatUtil.formatNumber(a[0]));
        map.put("stmtClose", FormatUtil.formatNumber(a[3]));
        map.put("ping", FormatUtil.formatNumber(a[4]));
        map.put("quit", FormatUtil.formatNumber(a[5]));
        map.put("other", FormatUtil.formatNumber(a[6]));
        map.put("kill", FormatUtil.formatNumber(a[8]));
        map.put("initDB", FormatUtil.formatNumber(a[7]));
        returnList.add(map);

        return page.setJustList(returnList, "根据代理ID获取正在执行的命令!");
    }

    /**
     * 根据代理ID获取connection
     *
     * @param proxyId
     * @return
     */
    @RequestMapping("/listConnection")
    @ResponseBody
    private ResponsePage listConnection(@RequestParam("proxyId") long proxyId) {
        ResponsePage page = getResponsePage();
        ProxyAdapterDAO perfAccesser = proxyService.getAccesser(proxyId, ProxyType.MANAGER);
        if (perfAccesser == null) {
            return page.setErrorMsg("找不到proxy node!");
        }
        if (!perfAccesser.checkConnection()) {
            return page.setErrorMsg("连接异常！");
        }
        List<ConnectionStatusVO> list = perfAccesser.listConnectionStatus();
        if (null != list) {
            ListSortUtil.sortConnections(list);
        }
        List<Map<String, Object>> returnList = new ArrayList<Map<String, Object>>();
        for (ConnectionStatusVO c : list) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("processor", c.getProcessor());
            map.put("id", c.getId());
            map.put("host", c.getHost());
            map.put("port", c.getPort());
            map.put("local_port", c.getLocal_port());
            map.put("schema", c.getSchema());
            map.put("charset", c.getCharset());
            map.put("netIn", FormatUtil.formatStore(c.getNetIn()));
            map.put("netOut", FormatUtil.formatStore(c.getNetOut()));
            map.put("aliveTime", FormatUtil.formatTime(c.getAliveTime() * 1000, 2));
            map.put("attempsCount", FormatUtil.formatNumber(c.getAttempsCount()));
            map.put("recvBuffer", FormatUtil.formatStore(c.getRecvBuffer()));
            map.put("sendQueue", c.getSendQueue());
            map.put("channel", c.getChannel());
            returnList.add(map);
        }
        return page.setJustList(returnList, "根据代理ID获取connection!");
    }
}
